from enum import Flag
import subprocess
import asyncio
import re
import time
import serial
import json
import pymysql
import threading
import queue

class MainBoard:
    """
    主控板基本情况数据获取类
    @getInfo：
    异步获取cpu,内存，硬盘，cpu温度的相关数据
    """

    def __init__(self):
        self.__cpuUsage = None
        self.__cpuTemp = None
        self.__memPer, self.__memTotal, self.__memUsed, self.__memFree = None, None, None, None
        self.__diskTotal, self.__diskUsed, self.__disFree, self.__diskPer = None, None, None, None

    async def __cmd_run(self, command: str, times: int = 3):
        proc = await asyncio.create_subprocess_shell(
            command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await proc.communicate()
        if stdout:
            return stdout.decode()
        if stderr:
            return stderr.decode()

    @property
    async def _cpu_usage(self) -> float:
        """
        返回值：返回CPU使用率
        """
        result = await self.__cmd_run("top -n1 | awk '/Cpu\(s\):/ {print $2}'")
        result.strip()
        result = float(result)
        return result

    @property
    async def _cpu_temp(self) -> float:
        """
        *需要使用树莓派，不然无法使用vcgencmd指令查询cpu温度
        返回值：返回CPU温度
        """
        result = await self.__cmd_run('vcgencmd measure_temp')
        result = result.replace("temp=", "").replace("'C\n", "")
        result = float(result)
        return result

    @property
    async def _mem_usage(self) -> tuple:
        """
        返回值：返回内存状况元组
        (内存使用率: float %,
        内存总量: float MB,
        内存使用量: float MB,
        内存剩余量: float MB)
        """
        result = await self.__cmd_run("free")
        line = result.split('\n')[1]
        RAM_TOTAL, RAM_USED, RAM_FREE = line.split()[1:4]
        RAM_TOTAL = round(int(RAM_TOTAL) / 1000, 2)
        RAM_USED = round(int(RAM_USED) / 1000, 2)
        RAM_FREE = round(int(RAM_FREE) / 1000, 2)
        RAM_USAGE = round(RAM_USED / RAM_TOTAL * 100, 2)
        return RAM_USAGE, RAM_TOTAL, RAM_USED, RAM_FREE

    @property
    async def _disk_usage(self) -> tuple:
        """
        返回值：返回一个硬盘状况元组
        (硬盘总大小: float,
        硬盘已使用: float,
        硬盘未使用: float,
        硬盘使用率: float %)
        """
        result = await self.__cmd_run("df -h /")
        line = result.split("\n")[1]
        DISK_TOTAL, DISK_USED, DISK_AVALIBLE, DISK_PERC = line.split()[1: 5]
        DISK_TOTAL = round(float(DISK_TOTAL.replace('G', '')), 2)
        DISK_USED = round(float(DISK_USED.replace('G', '')), 2)
        DISK_AVALIBLE = round(float(DISK_AVALIBLE.replace('G', '')), 2)
        DISK_PERC = round(float(DISK_PERC.replace('%', '')), 2)
        return DISK_TOTAL, DISK_USED, DISK_AVALIBLE, DISK_PERC

    @property
    async def _net_flu(self) -> dict:
        """
        @param: None
        @return: {
            "totalNetDevNum": (int)
            "devList" : [
                {
                    "devName":"eth0",
                    "receive":{
                        "bytes": (int),
                        "packets": (int),
                        "errs": (int),
                        "drop": (int),
                    },
                    "transmit":{
                        "bytes": (int),
                        "packets": (int),
                        "errs": (int),
                        "drop": (int),
                    }
                },
                ...
            ]
        }
        """
        result = await self.__cmd_run("cat /proc/net/dev")
        result = re.split(r'\n', result)
        contentList = []
        for i in range(2, len(result)-1):
            result_NL = result[i].split(':')
            # print(result_NL)
            devpropertyList = re.findall(r'(\d+)', result_NL[1])
            # print(devpropertyList)
            resultList = devpropertyList
            devName = result_NL[0].strip()
            recv_bytes = int(resultList[0])
            recv_packets = int(resultList[1])
            recv_errs = int(resultList[2])
            recv_drop = int(resultList[3])
            trans_bytes = int(resultList[8])
            trans_packets = int(resultList[9])
            trans_errs = int(resultList[10])
            trans_drop = int(resultList[11])
            contentList.append(
                {
                    "devName": devName,
                    "receive": {
                        "bytes": recv_bytes,
                        "packets": recv_packets,
                        "errs": recv_errs,
                        "drop": recv_drop,
                    },
                    "transmit": {
                        "bytes": trans_bytes,
                        "packets": trans_packets,
                        "errs": trans_errs,
                        "drop": trans_drop,
                    },
                }
            )
        realResultDic = {
            "totalNetDevNum": len(result)-2,
            "devList": contentList
        }
        return realResultDic

    @property
    def info(self) -> dict:
        """
        返回一个字典:
        __cpuUsage, __cpuTemp, __memPer, __memTotal
        memUsage, __memFree, __diskTotal, __diskUsed,
        __disFree, __diskPer, netInfo
        """
        asyncio.run(self._taskRun)
        return self.RESULT

    @property
    async def _taskRun(self):
        resultList = await asyncio.gather(self._cpu_usage,
                                          self._cpu_temp,
                                          self._mem_usage,
                                          self._disk_usage,
                                          self._net_flu,)
        # print(resultList)
        self.__cpuUsage = resultList[0]
        self.__cpuTemp = resultList[1]
        self.__memPer, self.__memTotal, self.__memUsed, self.__memFree = resultList[2]
        self.__diskTotal, self.__diskUsed, self.__disFree, self.__diskPer = resultList[3]
        self.netInfo = resultList[4]

        self.RESULT = {"cpuUsage": self.__cpuUsage,
                       "cpuTemp": self.__cpuTemp,
                       "memPer": self.__memPer,
                       "memTotal": self.__memTotal,
                       "memUsed": self.__memUsed,
                       "memFree": self.__memFree,
                       "diskTotal": self.__diskTotal,
                       "diskUsed": self.__diskUsed,
                       "disFree": self.__disFree,
                       "diskPer": self.__diskPer,
                       "netInfo": self.netInfo}

        return True

class NetWork:
    """
     4G网络模块

    @open_network: 打开网络
    @__runAT: 异步执行AT指令
    @getPhoneRingStatus: 获取电话信息
    @_getPhoneEmail: 获取电话短信
    """

    def __init__(self):
        # Scan 4G moudle load
        if self.__cmd_("ls -l /dev | grep ttyUSB") is None:
            raise RuntimeError("[CenterSystem_Network]: 网络模块没有检测到！")
        # Connect NetWork
        print("[CenterSystem_Network]: 网络模块硬件驱动有效！")
        self.__serial_normal = serial.Serial("/dev/ttyUSB3", 115200, timeout=1)
        self.__serial_gps = serial.Serial("/dev/ttyUSB1", 115200, timeout=1)
        print("[CenterSystem_Network]: 网络模块连接成功！")
        # 初始化4G串口
        self.__commandList = []
        # 初始化指令列表
        result = self.__runAT(
            ['AT+CMEE=2', 'AT+QURCCFG="URCPORT","usbat"', 'AT+CMGF=0'])

        result = self.__runAT(['ATI', 'AT+CPIN?', 'AT+CSQ?',
                               'AT+CREG?', 'AT+CGREG?', 'AT+COPS?', 'AT+QCCID', 'AT+CIMI'])
        # print(result)
        # 对模块进行初始化设置
        self.ManufacturerID = result[0][1]
        self.DeviceModule = result[0][2]
        self.FirmwareVersion = result[0][3]
        # 模块信息
        # self.PreferredOperator = result[5][1]
        # 网络信息
        self.SIM_IMSI = result[6][1]
        self.SIM_ICCID = result[7][1]
        # 获取最新短信索引
        res = self.__runAT(['AT+CSCA?'])[0]
        res_csca = res[1]
        res_number = re.search(r"\+\d+", res_csca).group()
        self.CENTER_NUMBER = res_number.replace("+86", '')
        # 短信息服务中心号码
        print("[CenterSystem_Network]: 模块初始化完成获得以下信息")
        print("[CenterSystem_Network]: 厂家:{} 型号:{} 版本:{}".format(
            self.ManufacturerID, self.DeviceModule, self.FirmwareVersion))
        print("[CenterSystem_Network]: SIM_IMSI:{} SIM_ICCID{}".format(
            self.SIM_IMSI, self.SIM_ICCID))
        print("[CenterSystem_Network]: 短信服务中心号码:{}".format(self.CENTER_NUMBER))
        # 读取短信并且将其合并同时检查是否有本地存储
        print("[CenterSystem_NetWork]: 启动新线程执行网络链接")
        print("[CenterSystem_Network]: 加载短信数据中....")
        self.dbStatus = False
        # ---------------以下是短信的合并以及去重------------------
        try:
            self.db = pymysql.connect(
                host='39.108.139.130',
                port=5001,
                user='root', password='keku520',
                database='small_car_4g')
            self.cursors = self.db.cursor()
            self.cursors.execute("SELECT VERSION()")
            data = self.cursors.fetchone()
            if data is not None:
                self.dbStatus = True
                print("[CenterSystem_Network]: 短信数据库连接成功!")
                # -------------发送短信获取指令，判断短信列表是否为空--Down--
                PDUTEXTLIST = []
                at_msgRes = self.__runAT(['AT+CMGL=4'])[0]
                at_msgRes_len = len(at_msgRes)
                if at_msgRes_len <= 3:
                    print("[CenterSystem_NetWork]: SIM卡上无任何短信数据，读取短信数据库中...")
                else:
                    # --------------不为空，执行算法，对短信进行处理--Down--
                    # TEXTLIST 为最终的处理结果
                    # --解码操作
                    print("[CenterSystem_NetWork]: 从SIM卡上获取短信成功，对短信源码进行处理中...")
                    for each in range(1, at_msgRes_len - 2):
                        if each % 2 == 0:
                            res = self.__pdu_text(at_msgRes[each])
                            PDUTEXTLIST.append(res)
                    TEXTLIST = []
                    selectList = []
                    # --合并操作
                    for one in PDUTEXTLIST:
                        if (one["reference"] is None) and (one["maxNo"] is None):
                            TEXTLIST.append({
                                'sent_site': one["sentSiteArea"],
                                'sent_phone': one['sentPhone'],
                                'recv_site': one["oaSiteArea"],
                                'recv_phone': one["recvPhone"],
                                'time_ticks': one["sctsTime"].split("|")[0],
                                'recv_text': one["udResult"],
                                'text_len': one["udl"]
                            })
                        elif one["reference"] not in selectList:
                            BreakList = []
                            for two in PDUTEXTLIST:
                                if one["reference"] == two["reference"] and one["maxNo"] == two["maxNo"]:
                                    BreakList.append(two)
                            breakListLen = len(BreakList)
                            for i in range(breakListLen):
                                for j in range(0, breakListLen - i - 1):
                                    j_num = int(BreakList[j]["currentNo"])
                                    j_num1 = int(BreakList[j + 1]["currentNo"])
                                    if j_num > j_num1:
                                        BreakList[j + 1], BreakList[j] = BreakList[j], BreakList[j + 1]
                            breakStr = ''
                            textLen = 0
                            for each in BreakList:
                                breakStr += each["udResult"]
                                textLen += each["udl"]
                            TEXTLIST.append({
                                'sent_site': one["sentSiteArea"],
                                'sent_phone': one['sentPhone'],
                                'recv_site': one["oaSiteArea"],
                                'recv_phone': one["recvPhone"],
                                'time_ticks': one["sctsTime"].split("|")[0],
                                'recv_text': breakStr,
                                'text_len': textLen,
                            })
                            selectList.append(one["reference"])
                    # --排序操作
                    for i in range(len(TEXTLIST)):
                        for j in range(0, len(TEXTLIST) - i - 1):
                            j_timeStmp = time.strptime(
                                TEXTLIST[j]["time_ticks"], "%Y-%m-%d %H:%M:%S")
                            j_timeStmp1 = time.strptime(
                                TEXTLIST[j + 1]["time_ticks"], "%Y-%m-%d %H:%M:%S")
                            if j_timeStmp > j_timeStmp1:
                                TEXTLIST[j + 1], TEXTLIST[j] = TEXTLIST[j], TEXTLIST[j + 1]
                    # ----------执行sql语句，将短信上传至MySql服务器上--Down--
                    for eachOne in TEXTLIST:
                        sqlStr = """INSERT INTO t_phone_email (
                                    e_s_site,e_s_phone,e_r_site,e_r_phone,e_time,e_text,e_text_len
                                ) values(
                                    "{}","{}","{}","{}","{}","{}","{}"
                                )""".format(
                            eachOne["sent_site"],
                            eachOne["sent_phone"],
                            eachOne["recv_site"],
                            eachOne["recv_phone"],
                            eachOne["time_ticks"],
                            eachOne["recv_text"],
                            eachOne["text_len"]
                        )
                        # print(sqlStr)
                        self.cursors.execute(sqlStr)
                        self.db.commit()
                # -----------获取数据表中的内容--Down--
                self.cursors.execute("select e_id,e_r_phone,e_time from t_phone_email")
                dbRecvData = self.cursors.fetchall()
                # ----------对数据表中的短信内容进行格式化处理--Down--
                self.MSG_INFO = []
                for eachOne in dbRecvData:
                    self.MSG_INFO.append({
                        "Id": eachOne[0],
                        "Senter": eachOne[1],
                        "Time": eachOne[2].strftime("%Y-%m-%d %H:%M:%S")
                    })
                # ----------执行AT指令，删除存储在SIM卡上的信息--Down
                self.delPhoneEmailAll()
                # ----------获取短信数量和索引ID--Down
                self.MSG_NUM = len(self.MSG_INFO)
                self.MSG_LASTINDEX = self.MSG_INFO[self.MSG_NUM - 1]["Id"]
                print("[CenterSystem_Network]: 短信数据获取成功!")
                print("[CenterSystem_Network]: 最新短信ID:{}".format(self.MSG_LASTINDEX))
                print("[CenterSystem_Network]: 短信数量为:{}".format(self.MSG_NUM))
                print("[CenterSystem_Network]: 系统初始化完成!")
            else:
                print("[CenterSystem_NetWork][Error]: 数据库连接失败!")
                self.dbStatus = False
        except:
            print("[CenterSystem_Catch][Error]: 数据库加载失败，短信初始化失败，无法获取短信信息!")
            self.dbStatus = False



    async def __cmd_run(self, command: str, times: int = 3):
        proc = await asyncio.create_subprocess_shell(
            command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await proc.communicate()
        if stdout:
            return stdout.decode()
        if stderr:
            return stderr.decode()

    def __cmd_(self, command: str, times: int = 3):
        sub = subprocess.Popen(command, shell=True,
                               stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        sub.wait(times)
        stdout, stderr = sub.communicate()
        if stdout and stderr:
            return stdout, stderr
        elif stdout:
            return stdout
        elif stderr:
            return stderr
        else:
            return None

    async def __at_normal(self, command: str, waittime: int = 5) -> list:
        """
        __at_normal 向串口执行AT指令

        私有类，不可修改

        Parameters
        ----------
        command : str
            需要发送的AT命令字符串
        waittime : int, optional
            超时时间，超时后结束循环, by default 5

        Returns
        -------
        list
            返回字符串列表
        """
        num = 0
        # await asyncio.sleep(0.01)
        if re.search(r'\^Z', command) == None:
            self.__serial_normal.write(
                (command + "\r").encode('ascii', 'ignore'))
        else:
            self.__serial_normal.write(command.replace(
                '^Z', chr(26)).encode('ascii', 'ignore'))
        result = b'\r\n'
        resultList = []
        while (result != b'OK\r\n' and result != b'ERROR\r\n' and (re.search('ERROR', result.decode()) is None)) and num <= waittime:
            result = self.__serial_normal.readline()
            if result == b'':
                num += 1
            elif result == b'> ':
                # print(result)

                resultList.append(result.decode().replace(
                    '\r', '').replace('\n', ''))
                # print("[CenterSystem]: 已进入发送短信模式，请输入pdu码后再加上^Z")
                return resultList
            else:
                resultList.append(result.decode().replace(
                    '\r', '').replace('\n', ''))
                # print(result)
        return resultList
        # print("-----------")

    async def __async_main(self, aws: list):
        """
        __async_main 异步AT指令执行口

        私有类，不可调用和修改

        Parameters
        ----------
        aws : list
            传入的AT字符串列表

        Returns
        -------
        list    
            返回二维字符串列表结果集
        """
        result = await asyncio.gather(*aws)
        return result

    def _text_pdu(self, recvPhone: int, content: str, sentPhone: int = 13800851500) -> tuple:
        """
        _text_pdu 将字符串文本转换成pdu编码，以此发送短信

        私有方法，不可修改，不可调用

        Parameters
        ----------
        recvPhone : int
            需要发送的手机号码
        content : str
            需要发送的字符串信息
        sentPhone : int, optional
            发送方的手机号码，没必要修改, by default 13800851500

        Returns
        -------
        tuple
            返回一个元组
                编码后字符串，信息长度
        """
        # SCA 1
        sca = '00'
        # PDU-Type 1
        pdutype = '11'
        # MR 1
        mr = '00'
        # DA 2-12
        da = ''
        recvPhoneStr = str(recvPhone)
        recvPhoneLen = len(recvPhoneStr)
        if recvPhoneLen == 11:
            recvPhoneList = list(recvPhoneStr + 'F')
            for i in range(0, len(recvPhoneList)):
                if i % 2 == 0:
                    recvPhoneList[i], recvPhoneList[i +
                                                    1] = recvPhoneList[i + 1], recvPhoneList[i]
                i += 1
            recvPhone = '0D9168' + ''.join(recvPhoneList)
            da = recvPhone
        else:
            recvPhoneList = list(recvPhoneStr + 'F')
            for i in range(0, len(recvPhoneList)):
                if i % 2 == 0:
                    recvPhoneList[i], recvPhoneList[i +
                                                    1] = recvPhoneList[i + 1], recvPhoneList[i]
                i += 1
            da_len = '0' + hex(recvPhoneLen).upper().replace('0X', '')
            da_type = '81'
            recvPhone = da_len + da_type + ''.join(recvPhoneList)
            da = recvPhone

        # PID 1
        pid = '00'
        # DCS 1
        dcs = '08'
        # VP 1
        vp = '00'
        # udl 1
        contentList = list(content)
        contentLen = len(contentList) * 2
        if contentLen <= 15:
            udl = '0' + hex(contentLen).upper().replace('0X', '')
        else:
            udl = hex(contentLen).upper().replace('0X', '')
        # ud
        ud = ''
        for each in contentList:
            json_res = json.dumps(each)[1:-1]
            if re.search(r'\\u', json_res) is not None:
                ud += json_res.replace("\\u", "")
            else:
                ud += hex(ord(json_res)).upper().replace('0X', '00')

        cmgs_part = pdutype + mr + da + pid + dcs + vp + udl + ud
        message = sca + cmgs_part
        message = message.upper()
        CMGS = int(len(cmgs_part) / 2)

        return message, CMGS

    def __pdu_text(self, text: str) -> dict:
        """
        __pdu_text 以下是接收方PDU解码格式

        Parameters
        ----------
        text : str
            pdu文本字符串

        Returns
        -------
        dict

        """
        # 以下实际位数*2
        # SCA 1-12
        sca_len = text[:2]  # 服务中心地址长度
        sca_type = text[2:4]  # 短信中心地址类型 81未知 91国际 A1国内
        sca_add = text[4:(int(sca_len)*2-2)+4]
        sca_end_index = (int(sca_len)*2-2)+4
        # print((sca_len, sca_type, sca_add, sca_end_index))
        sentSiteArea = ''
        if sca_type == '91':
            sentSiteArea = '国际'
        elif sca_type == 'A1':
            sentSiteArea = '国内'
        else:
            sentSiteArea = '未知'
        sentPhone = list(sca_add[2:])
        # print(sentPhone, len(sentPhone))
        for i in range(0, len(sentPhone) - 1):
            if i == len(sentPhone) - 1:
                break
            if i % 2 == 0:
                # print(i)
                temp = sentPhone[i]
                sentPhone[i] = sentPhone[i + 1]
                sentPhone[i + 1] = temp
        sentPhone.pop(len(sentPhone) - 1)
        if sentPhone[:2] == ['8', '6']:
            sentPhone = sentPhone[2:]
        sentPhone = ''.join(sentPhone)
        sentPhoneLen = len(sentPhone)
        # print((sentSiteArea, sentPhone, sentPhoneLen))

        # PDUType 1
        pdutype = text[sca_end_index:sca_end_index + 2]  # 发送方 11h #接收方 24h
        pdutype_bin = bin(int(str('0x' + pdutype), 16)).replace('0b', '')
        if 8-len(pdutype_bin) != 0:
            zero = '0' * (8-len(pdutype_bin))
            pdutype_bin = zero + pdutype_bin
        pdutype_RP = pdutype_bin[0]  # 应答路径是否设置 0 false 1 true
        pdutype_UDHI = pdutype_bin[1]
        pdutype_SRI = pdutype_bin[2]
        pdutype_MMS = pdutype_bin[5]
        # pdutype_SSR = pdutype_bin[2]
        # pdutype_VPF1 = pdutype_bin[3]
        # pdutype_VPF2 = pdutype_bin[4]
        # pdutype_RD = pdutype_bin[5]
        # pdutype_MTI1 = pdutype_bin[6]
        # pdutype_MTI2 = pdutype_bin[7]
        pdutype_end = sca_end_index + 2
        # print((pdutype, pdutype_bin))
        pduResult = ''
        # print(pdutype_RP)
        pduResult += ('应答路径未设置-' if pdutype_RP == '0' else '应答路径已设置-')
        pduResult += ('用户数据部分不包含头信息-' if pdutype_UDHI ==
                      '0' else '用户数据开始部分包含用户头信息-')
        pduResult += ('状态报告不会返回-' if pdutype_SRI == '0' else '状态报告会返回-')
        pduResult += ('有更多的消息需要发送-' if pdutype_MMS == '0' else '没有更多的消息需要发送-')
        # print((pdutype, pduResult))

        # OA 2-12
        oa_len = text[pdutype_end: pdutype_end + 2]  # 接收方地址长度，不包括91
        oa_type = text[pdutype_end + 2: pdutype_end + 4]  # 接收方地址类型
        oa_type_end = pdutype_end + 4
        oa_add = text[oa_type_end: pdutype_end +
                      4 + int('0x' + oa_len, 16) + 1]  # 接收方地址
        if 'F' not in oa_add:
            oa_add = text[oa_type_end: pdutype_end +
                          4 + int('0x' + oa_len, 16)]
            oa_end = pdutype_end + 4 + int('0x' + oa_len, 16)
        else:
            oa_end = pdutype_end + 4 + int('0x' + oa_len, 16) + 1
        # print((oa_len, oa_type, oa_add))
        oaSiteArea = ''
        if oa_type == '91':
            oaSiteArea = '国际'
        elif oa_type == 'A1':
            oaSiteArea = '国内'
        else:
            oaSiteArea = '未知'
        recvPhone = list(oa_add)
        for i in range(0, len(recvPhone) - 1):
            if i == len(recvPhone) - 1:
                break
            if i % 2 == 0:
                # print(i)
                temp = recvPhone[i]
                recvPhone[i] = recvPhone[i + 1]
                recvPhone[i + 1] = temp
        recvPhone.pop(len(recvPhone) - 1)
        if recvPhone[:2] == ['8', '6']:
            recvPhone = recvPhone[2:]
        recvPhone = ''.join(recvPhone)
        recvPhoneLen = len(recvPhone)
        # print((oaSiteArea, recvPhone, recvPhoneLen))

        # PID 1
        pid = text[oa_end: oa_end + 2]  # 通常为00
        pid_end = oa_end + 2
        # print((pid))

        # DCS 1
        dcs = text[pid_end: pid_end + 2]
        # 00h 7bit 默认字符集
        # F6h 8bit数据编码 Class1
        # 08h USC2（16bit）双字节字符集
        dcs_end = pid_end + 2
        # print((dcs))
        dcsResult = ''
        if dcs == '00':
            dcsResult = '7bit'
        elif dcs == 'F6':
            dcsResult = '8bit'
        elif dcs == '08':
            dcsResult = '16bit'
        # print((dcsResult))

        # SCTS 7
        # -----------------------
        # 注意： 此处使用了List来当作指针，多进程可能会出现问题
        # -----------------------
        def transform(dataAdd):
            temp = dataAdd[0]
            dataAdd[0] = dataAdd[1]
            dataAdd[1] = temp

        scts = text[dcs_end: dcs_end + 14]
        scts_year = list(scts[:2])
        scts_month = list(scts[2: 4])
        scts_day = list(scts[4: 6])
        scts_hour = list(scts[6: 8])
        scts_min = list(scts[8: 10])
        scts_sec = list(scts[10: 12])
        scts_are = list(scts[12: 14])
        scts_end = dcs_end + 14
        transform(scts_year)
        transform(scts_month)
        transform(scts_day)
        transform(scts_hour)
        transform(scts_min)
        transform(scts_sec)
        transform(scts_are)
        # print((scts_year, scts_month, scts_day, scts_hour, scts_min, scts_sec, scts_are))
        sctsTime = '20{}-{}-{} {}:{}:{}|AREA:{}'.format(
            ''.join(scts_year), ''.join(scts_month), ''.join(scts_day),
            ''.join(scts_hour), ''.join(scts_min), ''.join(scts_sec),
            ''.join(scts_are))
        # print((sctsTime))

        # UDL 1
        udl = text[scts_end: scts_end + 2]  # 用户数据的长度
        udl_end = scts_end + 2

        # UDH 6 - 7
        # UDHL 1 IEI 1 IEDL 1 REN 1-2 MAXN 1 CURNTN 1
        if pdutype_UDHI != '0':
            udh_udhl = text[udl_end: udl_end + 2]
            udh_iei = text[udl_end + 2: udl_end + 4]
            udh_iedl = text[udl_end + 4: udl_end + 6]
            udh_ren_start = 0
            udh_ren_end = 0
            if udh_iei == '00':
                udh_lens = 6
                udh_ren_start = udl_end + 6
                udh_ren_end = udl_end + 8
                udh_ren = text[udh_ren_start: udh_ren_end]
            elif udh_iei == '08':
                udh_lens = 7
                udh_ren_start = udl_end + 6
                udh_ren_end = udl_end + 10
                udh_ren = text[udh_ren_start: udh_ren_end]
            udh_maxn = text[udh_ren_end: udh_ren_end + 2]
            udh_curntn = text[udh_ren_end + 2: udh_ren_end + 4]
            udh_end = udh_ren_end + 4
            ud = text[udh_end:]
            udl_truly_len = int((int('0x' + udl, 16) - udh_lens) * 2 / 4)
        else:
            udh_ren = None
            udh_maxn = None
            udh_curntn = None
            ud = text[udl_end:]
            udl_truly_len = int(int('0x' + udl, 16) * 2 / 4)

        # UD_SM
        ud_list = re.findall(r'.{4}', ud)
        ud_new_list = []
        for each in ud_list:
            each = '\\u' + each.lower()
            # print(each)
            ud_new_list.append(each)
            # ud_new_list.append('')
        ud_string = ''.join(ud_new_list)
        ud_string = '"' + ud_string + '"'
        udResult = json.loads(ud_string, encoding='utf-32')
        # print((udResult))

        resultDic = {'sentSiteArea': sentSiteArea,
                     'sentPhone': sentPhone,
                     'sentPhoneLen': sentPhoneLen,
                     'pduResult': pduResult,
                     'oaSiteArea': oaSiteArea,
                     'recvPhone': recvPhone,
                     'recvPhoneLen': recvPhoneLen,
                     'dcsResult': dcsResult,
                     'sctsTime': sctsTime,
                     'udl': udl_truly_len,
                     'reference': udh_ren,
                     'maxNo': udh_maxn,
                     'currentNo': udh_curntn,
                     'udResult': udResult}
        return resultDic

    def _open_network(self):
        """
        _open_network 启动网络

        Raises
        ------
        RuntimeError
            连接超时后自动报错
        """
        print("[CenterSystem_Network]: 正在启动网络连接!")
        lasttime = time.time()
        self.__cmd_("nohup sudo wvdial lan1 > /home/pi/Documents/Logs/netrun.log 2>&1 &")
        times = 0
        res = self.__cmd_("sudo ip route | grep via").decode()
        res = re.search(r'\d+\.\d+\.\d+\.\d+', res).group()
        while True:
            if times >= 50:
                print("[CenterSystem_Network]: 网络连接超时！")
                break
            if self.__cmd_("cat /home/pi/Documents/Logs/netrun.log | grep IP") is not None:
                break
            time.sleep(1)
            times += 1
        nowtime = time.time()
        print("[CenterSystem_Network]: 网络连接成功。")
        print("[CenterSystem_Network]: 共耗时{}s!".format(
            round(nowtime-lastTime, 3)))
        # Start frpc
        self.__cmd_("sudo ip route del default via {0}".format(res))
        self.__cmd_("sudo ip route add default via 10.64.64.64")
        print("[CenterSystem_Network]: 路由切换成功。")

    def __runAT(self, strList: list, waittime: int = 3) -> list:
        """
        __runAT 异步运行AT指令集

        Parameters
        ----------
        strList : list
            需要传入的指令集合

        Returns
        -------
        list
            返回指令运行完成后的二维列表
        """
        for each in strList:
            self.__commandList.append(
                self.__at_normal(each, waittime=waittime))
        resultList = asyncio.run(self.__async_main(self.__commandList))
        self.__commandList = []
        return resultList

    def getPhoneRingStatus(self) -> int:
        """
        getPhoneRingStatus 获取手机拨号状态

        0: 待机中, 1: 来电, 2:拨号

        Returns
        -------
        int
            返回的拨号状态
        """
        result = self.__runAT(['AT+CLCC'])
        # print(result)
        result = result[0][2]
        status = result.split(',')[5]
        # print(status)
        if status != '""':
            result = result.replace('CLCC：', '')
            resultList = result.split(',')
            callStatus = resultList[6]
            result = resultList[5]
            resultLen = len(result)
            # print(resultLen)
            if resultLen == 13 and callStatus == '128':
                print("[CenterSystem_Network]：来电了！->", result)
                return 1
            elif callStatus == '129':
                print("[CenterSystem_NetWork]: 目前在打电话->", result)
                return 2
        else:
            print("[CenterySystem_Network]: 电话待机中...")
            return 0

    def endPhone(self) -> bool:
        """
        endPhone 挂断电话

        Returns
        -------
        bool
            返回是否成功挂断电话
        """
        result = self.__runAT(['ATH'])
        if result[0][1] == 'OK':
            print("[CenterSystem_Network]：电话挂断成功！")
            print("[CenterSystem_Network]：目前电话状态为->",
                  self.getPhoneRingStatus())
            return True
        else:
            print("[CenterSystem_Network]：电话挂断失败！")
            return False

    def getPhoneEmail(self, index: int) -> tuple:
        """
        getPhoneEmail 从数据库中获取手机短信

        Parameters
        ----------
        index : int
            索引号码

        Returns
        -------
        tuple
            发送者号码，短信内容，发送时间
        """        ""
        sql = "select e_text from t_phone_email where e_id = {};".format(
            index)
        self.cursors.execute(sql)
        resText = self.cursors.fetchone()[0]
        resSenter = self.MSG_INFO[index-1]["Senter"]
        resTime = self.MSG_INFO[index-1]["Time"]
        return resSenter, resText, resTime

    def flushPhoneEmail(self) -> bool:
        # -------------发送短信获取指令，判断短信列表是否为空--Down--
        try:
            PDUTEXTLIST = []
            at_msgRes = self.__runAT(['AT+CMGL=4'])[0]
            at_msgRes_len = len(at_msgRes)
            if at_msgRes_len <= 3:
                return False
            else:
                # --------------不为空，执行算法，对短信进行处理--Down--
                # TEXTLIST 为最终的处理结果
                # --解码操作
                for each in range(1, at_msgRes_len-2):
                    if each % 2 == 0:
                        res = self.__pdu_text(at_msgRes[each])
                        PDUTEXTLIST.append(res)
                TEXTLIST = []
                selectList = []
                # --合并操作
                for one in PDUTEXTLIST:
                    if (one["reference"] is None) and (one["maxNo"] is None):
                        TEXTLIST.append({
                            'sent_site': one["sentSiteArea"],
                            'sent_phone': one['sentPhone'],
                            'recv_site': one["oaSiteArea"],
                            'recv_phone': one["recvPhone"],
                            'time_ticks': one["sctsTime"].split("|")[0],
                            'recv_text': one["udResult"],
                            'text_len': one["udl"]
                        })
                    elif one["reference"] not in selectList:
                        BreakList = []
                        for two in PDUTEXTLIST:
                            if one["reference"] == two["reference"] and one["maxNo"] == two["maxNo"]:
                                BreakList.append(two)
                        breakListLen = len(BreakList)
                        for i in range(breakListLen):
                            for j in range(0, breakListLen-i-1):
                                j_num = int(BreakList[j]["currentNo"])
                                j_num1 = int(BreakList[j+1]["currentNo"])
                                if j_num > j_num1:
                                    BreakList[j+1], BreakList[j] = BreakList[j], BreakList[j+1]
                        breakStr = ''
                        textLen = 0
                        for each in BreakList:
                            breakStr += each["udResult"]
                            textLen += each["udl"]
                        TEXTLIST.append({
                            'sent_site': one["sentSiteArea"],
                            'sent_phone': one['sentPhone'],
                            'recv_site': one["oaSiteArea"],
                            'recv_phone': one["recvPhone"],
                            'time_ticks': one["sctsTime"].split("|")[0],
                            'recv_text': breakStr,
                            'text_len': textLen,
                        })
                        selectList.append(one["reference"])
                # --排序操作
                for i in range(len(TEXTLIST)):
                    for j in range(0, len(TEXTLIST)-i-1):
                        j_timeStmp = time.strptime(
                            TEXTLIST[j]["time_ticks"], "%Y-%m-%d %H:%M:%S")
                        j_timeStmp1 = time.strptime(
                            TEXTLIST[j+1]["time_ticks"], "%Y-%m-%d %H:%M:%S")
                        if j_timeStmp > j_timeStmp1:
                            TEXTLIST[j+1], TEXTLIST[j] = TEXTLIST[j], TEXTLIST[j+1]
                # ----------执行sql语句，将短信上传至MySql服务器上--Down--
                for eachOne in TEXTLIST:
                    sqlStr = """INSERT INTO t_phone_email (
                        e_s_site,e_s_phone,e_r_site,e_r_phone,e_time,e_text,e_text_len
                    ) values(
                        "{}","{}","{}","{}","{}","{}","{}"
                    )""".format(
                        eachOne["sent_site"],
                        eachOne["sent_phone"],
                        eachOne["recv_site"],
                        eachOne["recv_phone"],
                        eachOne["time_ticks"],
                        eachOne["recv_text"],
                        eachOne["text_len"]
                    )
                    # print(sqlStr)
                    self.cursors.execute(sqlStr)
                    self.db.commit()
            # -----------获取数据表中的内容--Down--
            self.cursors.execute(
                "select e_id,e_r_phone,e_time from t_phone_email")
            dbRecvData = self.cursors.fetchall()
            # ----------对数据表中的短信内容进行格式化处理--Down--
            self.MSG_INFO = []
            for eachOne in dbRecvData:
                self.MSG_INFO.append({
                    "Id": eachOne[0],
                    "Senter": eachOne[1],
                    "Time": eachOne[2].strftime("%Y-%m-%d %H:%M:%S")
                })
            # ----------执行AT指令，删除存储在SIM卡上的信息--Down
            self.delPhoneEmailAll()
            # ----------获取短信数量和索引ID--Down
            self.MSG_NUM = len(self.MSG_INFO)
            self.MSG_LASTINDEX = self.MSG_INFO[self.MSG_NUM - 1]["Id"]
            return True
        except:
            return False

    def delPhoneEmailAll(self) -> bool:
        res = self.__runAT(['AT+CMGD=1, 4'], 5)
        res_stat = res[0][1]
        if res_stat == 'OK':
            # print("[CenterSystem_Network]: 所有短信删除成功！")
            return True
        else:
            # print("[CenterSystem_Network]: 所有短信删除失败！")
            return False

    def sendPhoneEmail(self, recvPhone: int, content: str) -> bool:
        text, leng = self._text_pdu(recvPhone, content)
        res_first = self.__runAT(['AT+CMGF=0', 'AT+CSCS="GSM"'])
        if res_first[0][1] == 'OK' and res_first[1][1] == 'OK':
            print("[CenterSystem_Network]: 短信初始化成功，即将发送短信!")
            res_sent = self.__runAT(["AT+CMGS={}".format(leng), text+'^Z'], 10)
            try:
                if res_sent[1][3] == 'OK':
                    print("[CenterSystem_Network]: 短信发送成功->{}".format(recvPhone))
                    return True
                else:
                    print("[CenterSystem_Network]: 短信发送失败，请检查数据是否正确，号码是否正确!")
                    return False
            except:
                res_sent = self.__runAT(['^Z'])
                if res_sent[1][3] == 'OK':
                    print("[CenterSystem_Network]: 短信发送成功->{}".format(recvPhone))
                    return True
                else:
                    print("[CenterSystem_Network]: 短信拯救失败!请重启模块!")
                    return False
        else:
            print("[CenterSystem_Network]: 短信初始化失败，发送短信失败!")
            return False

    def callPhone(self, recvPhone: int) -> bool:
        """
        callPhone 拨打电话

        Parameters
        ----------
        recvPhone : int
            电话号码

        Returns
        -------
        bool
            返回是否拨打成功
        """
        result = self.__runAT(["ATD{};".format(recvPhone)])
        done_sign = result[0][1]
        if done_sign == 'OK' and self.getPhoneRingStatus() == 2:
            print("[CenterSystem_Network]: 主动拨号成功!")
            return True
        else:
            print("[CenterSystem_Network]: 主动拨号失败，请重试!")
            return False

    def checkEmailComplete(self) -> bool:
        PDUTEXTLIST = []
        at_msgRes = self.__runAT(['AT+CMGL=4'])[0]
        at_msgRes_len = len(at_msgRes)
        # print(at_msgRes_len)
        if at_msgRes_len <= 3:
            return False
        else:
            for each in range(1, at_msgRes_len-2):
                if each % 2 == 0:
                    res = self.__pdu_text(at_msgRes[each])
                    PDUTEXTLIST.append(res)
            num = 0
            sign = PDUTEXTLIST[0]["reference"]
            maxNo = int(PDUTEXTLIST[0]['maxNo'])
            # print(sign, maxNo)
            if maxNo is None:
                return False
            for eachOne in PDUTEXTLIST:
                # print(eachOne["reference"])
                if eachOne["reference"] == sign:
                    num += 1
            # print(num)
            if num >= maxNo:
                return True
            else:
                return False

    def resetNetworkFlu(self, waittime=5) -> dict:
        # nowIndex = self.MSG_LASTINDEX
        print("[CenterSystem_Network]: 刷新流量中，清稍等....")
        if self.sendPhoneEmail(10010, 'cxll'):
            while waittime >= 0:
                if self.checkEmailComplete():
                    self.flushPhoneEmail()
                    print("[CenterSystem_Network]: 流量获取成功!")
                    print("[CenterSystem_Network]: 处理流量数据中...")
                    resSenter, resText, resTime = self.getPhoneEmail(
                        self.MSG_LASTINDEX)
                    resText = resText.split('\n')[1]
                    print(resText)
                    resTotal = re.search(
                        r'总流量\d+[KBM]+(\d+[KBM]+)?', resText).group()
                    resTotal = re.search(
                        r'\d+[KBM]+(\d+[KBM]+)?', resTotal).group()
                    resUsed = re.search(
                        r'已使用\d+[KBM]+(\d+[KBM]+)?', resText).group()
                    resUsed = re.search(
                        r'\d+[KBM]+(\d+[KBM]+)?', resUsed).group()
                    resSpare = re.search(
                        r'剩余\d+[KBM]+(\d+[KBM]+)?', resText).group()
                    resSpare = re.search(
                        r'\d+[KBM]+(\d+[KBM]+)?', resSpare).group()
                    sql = """INSERT INTO t_phone_flu (flu_time,flu_total,
                    flu_used,flu_space) values("{}","{}","{}","{}")""".format(resTime, resTotal, resUsed, resSpare)
                    self.cursors.execute(sql)
                    self.db.commit()
                    return True
                time.sleep(1)
                waittime -= 1
            print("[CenterSystem_Network]: {}s已过，没有收到邮件".format(waittime))
            return False
        else:
            print("[CenterSystem_Network]: 流量获取短信发送失败，清重试!")
            return False

    def getNetworkFlu(self) -> tuple:
        sql = """SELECT flu_time,flu_total,flu_used,flu_space FROM t_phone_flu
        WHERE (SELECT max(flu_id) FROM t_phone_flu);
        """
        self.cursors.execute(sql)
        res = self.cursors.fetchone()
        resTime = res[0].strftime("%Y-%m-%d %H:%M:%S")

        def searchGB(resText):
            try:
                Mb = int(re.search(r'\d+MB', resText).group().replace('MB', ''))
            except:
                Mb = 0
            try:
                Kb = int(re.search(r'\d+KB', resText).group().replace('KB', ''))
            except:
                Kb = 0
            return round((Mb * 1024 + Kb) / 1024 / 1024, 3)

        resTotal = searchGB(res[1])
        resUsed = searchGB(res[2])
        resSpace = searchGB(res[3])
        return resTime, resTotal, resUsed, resSpace

    def getNetworkSignal(self) -> int:
        res = self.__runAT(['AT+CSQ'])[0]
        reslist = re.search(r'\d+,\d+', res[1]).group().split(',')
        if reslist[0] == '99':
            dbm = -114
        else:
            dbm = -113 + int(reslist[0])*2
        stat = reslist[1] + '%'
        return dbm, stat

class Battery:
    """
    电池模块信息数据获取类
    @
    """

    def __init__(self):
        self.ser = serial.Serial("/dev/ttyAMA0", 9600, timeout=3)
        self.result = ''
        self.que = queue.Queue(5)
        self.task = threading.Thread(target=self.getResult, daemon=True)
        self.task.start()
        
    def getResult(self):
        while True:
            try:
                self.result = self.ser.readline().decode().replace('\n', '')
                if re.search(r'^\$ SmartUPS V.+,Vin .+,BATCAP \d+,Vout \d+ \$$', self.result) is None:
                    continue
                else:
                    self.result = self.result.replace('$', '').replace(' ', '')
                    resultList = self.result.split(',')
                    version = resultList[0].replace('SmartUPS', '')
                    recharge = resultList[1].replace('Vin', '')
                    power = resultList[2].replace('BATCAP', '')
                    vount = resultList[3].replace('Vout', '')
                    if not self.que.full():
                        self.que.put((version, recharge, power, vount))
                        self.que.task_done()
                    else:
                        self.que.get()
                        self.que.put((version, recharge, power, vount))
                        self.que.task_done()
            except:
                self.ser.close()
                self.ser.open()
    
    @property
    def getInfo(self):
        self.que.join()
        return self.que.get() 


if __name__ == '__main__':
    lastTime = time.time()
    # power = Battery()
    board = MainBoard()
    print(board.info)
    # while True:
    #     try:
    #         res = board.getInfo['netInfo']
    #         lastSec_receive_bytes = int(res['devList'][4]['receive']['bytes'])
    #         lastSec_transmit_bytes = int(res['devList'][4]['transmit']['bytes'])
    #         time.sleep(1)
    #         res = board.getInfo['netInfo']
    #         nowSec_receive_bytes = int(res['devList'][4]['receive']['bytes'])
    #         nowSec_transmit_bytes = int(res['devList'][4]['transmit']['bytes'])
    #         res_receive = int((nowSec_receive_bytes - lastSec_receive_bytes) / 1024)
    #         res_transmit = int((nowSec_transmit_bytes - lastSec_transmit_bytes) / 1024)
    #         print("receive: {} KB/s | sent: {} KB/s".format(res_receive, res_transmit)) 
    #     except KeyboardInterrupt:
    #         break
    # net = NetWork()
    # res = net.getNetworkSignal()
    # print(res)
    # text = net.getPhoneEmail(21)
    # print(text)
    # print('即将开始获取信息')
    # for i in range(0,10):
    #     time.sleep(1)
    #     print(power.getInfo)
    # net.open_network()
    # res = net.resetNetworkFlu(waittime=10)
    # print(res)
    # net.open_network()
    print(time.time()-lastTime)